package com.example.springbootwebserviceproxy.controller;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.webservice.SoapClient;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.springbootwebserviceproxy.controller.vo.WebServiceApiInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import java.util.Objects;

/**
 * MockController.
 *
 * @author <a href='mailto:likeguo@apache.com'> likeguo </a>
 */
@RestController
@RequestMapping("convert")
public class WebServiceApiConvertRestController {
    
    @PostMapping("/2")
    public String mock2(@RequestBody WebServiceApiInfo bean) {
        
        try {
       
            // 创建动态客户端
            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
            
            QName qName = new QName(bean.getNamespace(), bean.getMethod());
            
            Client client = dcf.createClient(bean.getServiceUrl());
            
            
            ObjectMapper mapper = new ObjectMapper();
            
            Object[] objects = client.invoke(qName, bean.getParams().values().toArray());
            System.out.println("返回数据:" + mapper.writeValueAsString(objects));
            return mapper.writeValueAsString(objects);
        } catch (java.lang.Exception e) {
            e.printStackTrace();
            return "error:" + e.getMessage();
        }
    }
    
    
    @PostMapping("/")
    public Object convert(@RequestBody WebServiceApiInfo info) {
        try {
            // 新建客户端
            SoapClient client = SoapClient.create(info.getServiceUrl())
                    .setMethod("" + info.getMethod(), info.getNamespace());
            // 构建转换参数
            addParams(info, client);
            
            Console.log("web service 服务代理 send:");
            Console.log("web Service address: " + info.getServiceUrl());
            Console.log(client.getMsgStr(true));
            // 发起WebService调用
            final String send = client.send(false);
            
            Console.log("web Service 响应体（xml）：");
            final Document document = XmlUtil.parseXml(send);
            Console.log(XmlUtil.format(document));
            final Node returnNode = find(document, "getSupportCityResult");
            final String res = JSONUtil.toJsonStr(XmlUtil.xmlToMap(returnNode));
            Console.log("转发给客户端（Json）:");
            Console.log(JSONUtil.formatJsonStr(res));
            return JSONUtil.parseObj(res);
        } catch (Exception e) {
            e.printStackTrace();
            return "error:" + e.getMessage();
        }
    }
    
    private void addParams(WebServiceApiInfo info, SoapClient client) {
        info.getParams().forEach((k, v) -> {
            try {
                final SOAPBodyElement argsRoute = client.getMethodEle();
                if (JSONUtil.isTypeJSONObject(Objects.toString(v))) {
                    final SOAPElement p = argsRoute.addChildElement(k, "web", "http://server.springbootwebserviceserver.server.service.web.example.com/");
                    final JSONObject json = JSONUtil.parseObj(v);
                    json.forEach(node -> {
                        try {
                            final SOAPElement element = p.addChildElement(node.getKey());
                            element.setValue(Objects.toString(node.getValue()));
                        } catch (SOAPException e) {
                            throw new RuntimeException(e);
                        }
                    });
                } else {
                    argsRoute.addChildElement(k).setValue(Objects.toString(v));
                }
            } catch (SOAPException e) {
                throw new RuntimeException(e);
            }
        });
    }
    
    private Node find(Node node, String name) {
        if (Objects.equals(node.getNodeName(), name)) {
            return node;
        }
        final NodeList childNodes = node.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            final Node item = childNodes.item(i);
            if (item.hasChildNodes()) {
                return find(node.getFirstChild(), name);
            }
        }
        return null;
    }
}
